/************************************************************
                         Proj
Copyright (c) The Sanger Centre

contig[i].projmsg per line
Proj.msg2[2] at top
**************************************************************/
#include "clam.h"
#include <malloc.h>
#include <float.h>
#include <gtk/gtkwidget.h>  /*fred 3/5/03*/
#include <ctype.h>

extern GtkWidget *ctg_window;  /*fred 3/5/03*/

extern int Zbatch_flag;
extern int Zrule_sim;    /* simulations */
extern int PRTMESS;
extern void show_help();

extern void Zsummary();
extern Graph gproj, gclean;
extern void ZeditProj(), ZupdateProj();
extern void displaymarker(); /* fpp */
extern void getdatehead(), clearMsg(), ZmapHigh();
static void By_ctg();
void displayProj();

static int chrtype=0;
static int nopop=0, displaytype=0;
static int PLsort=0;
static char Msg[5000];
static int projbar, projupkey, projdownkey;
static int highline, startline, numlines;
static float projrange, projboxstart, projbottom, projtop=6.0;
static float projpage, projmaxpage, pagesize;

static int numPL=0, maxPL=0;
static struct Proj_line {
   int n, n2;
   int index;
   int box;
   int draft;
   char msg[MSGSIZE*2+1];
} *PL;

static int scrollpicked();
static void gotoHigh(), compute_PL(), By_size(), proj_counts(), By_len(), By_draft();
static void projwin(), proj_framework(), proj_ends(), proj_seq(), proj_keyset();
static void proj_results(), By_pos(), By_score();
void Zproj_resutls();

#define NOPTIONS 11
#define ByCtg 0
#define ByClones 1
#define ByLen 2
#define ByCounts 3
#define BySeq 4
#define ByKey 5
#define ByPos 6
#define ByScore 7
#define ByDraft 8
#define Results 9
#define FW 10
#define End 11

void editHighCtg() { 
void thisCtgRemark(); 
  if (highline == -1) return; /* cari 1mar04 */
  if (PL[highline].index > 0 && PL[highline].index <= max_contig)
       thisCtgRemark(PL[highline].index); 
}
void setDisplayType(int t)
{
  displaytype = t;
}
static void pick_ctg() {displaytype=ByCtg; projwin(1);}
static void pick_size() {displaytype=ByClones; projwin(1);}
static void pick_draft() {displaytype=ByDraft; projwin(1);}
static void pick_len() {displaytype=ByLen; projwin(1);}
static void pick_counts() {displaytype=ByCounts; projwin(1);}
static void pick_seq() {displaytype=BySeq; projwin(1);}
static void pick_key() {displaytype=ByKey; projwin(1);}
static void pick_results() {displaytype=Results; projwin(1);}
static void pick_fw() {displaytype=FW; projwin(1);}
static void pick_end() {displaytype=End; projwin(1);}
static void pick_pos() {displaytype=ByPos; projwin(1);}
static void pick_score() {displaytype=ByScore; projwin(1);}

static MENUOPT projmenu[] = {
      { pick_ctg,"By Contig Number"},
      { pick_size,"By Contig Size"},
      { pick_len,"By Contig Length"},
      { pick_counts,"By Clone Counts"},
      { pick_seq,"By Sequence"},
      { pick_key,"By KeySet"},
      { pick_pos,"Show Position"},
      { pick_score,"By Low Score"},
      { pick_draft,"By Draft"},
      { pick_results,"By Results"},
      { pick_fw,"Framework"},
      { pick_end,"End Sequence"},
      { 0, 0}};

static char optlabel[NOPTIONS+1][20] = {"By ctg..  ","By size.. ", "By length..",
             "Counts..  ", "Sequence..", "KeySet..  ", "Position..",
             "Low Score",  "Draft..    ", "Results...", "Framework..",  "Ends..    "};

/* CAS 2-2-3  Add new msg stuff */
static int CtgMsgFlag=0; 
static void ctgMsg1() {CtgMsgFlag=0;  projwin(1);}
static void ctgMsg2() {CtgMsgFlag=1;  projwin(1);}
static void ctgMsg3() {CtgMsgFlag=2;  projwin(1);}

static MENUOPT ctgMsgmenu[] = {
      { ctgMsg1,"Chr_Remark  "},
      { ctgMsg2,"User_Remark "},
      { ctgMsg3,"Trace_Remark"},
      { 0, 0}};
static char chrlabel[3][20] = {"Chr_Remark  ","User_Remark ",
                    "Trace_Remark"};

static int resulttype=0; /* 0 = c2am, 1&2 = zap */

/***********************************************************
                    DEF: quitProj
***********************************************************/
void quitProj()
{
  displaytype=0;
  if (PL!=NULL) free(PL); 
  PL=NULL;
  numPL = maxPL=0;
  if(graphActivate(gproj)) graphDestroy();
  if(graphActivate(gclean)) graphDestroy();
  if(graphActivate(gtextwhole)) graphDestroy();
}
/***********************************************************
                    DEF: printProj
***********************************************************/
void printProj()
{
FILE *fp, *graphQueryOpen();
register int i;

    fp = graphQueryOpen(mergedir, mergefile, "","w","Choose output file");
    if(fp==0)  return;
    
    fprintf(fp,"%s\n", Proj.msg2[2]);
    fprintf(fp,"%s\n", Proj.msg2[0]);
    fprintf(fp,"%s\n\n", Proj.msg2[1]);
    fprintf(fp,"%s\n", Proj.msg2[3]);
    if (displaytype<=Results) {
         for (i=0; i<numPL; i++) 
             fprintf(fp,"Ctg%-5d %s\n",PL[i].index,PL[i].msg);
    }
    else {
        for (i=0; i<numPL; i++) 
           fprintf(fp,"%-14s %s\n",
              arr(markerdata, PL[i].index, MARKER).marker, PL[i].msg);
    }
    fclose(fp);
}
/**********************************************************
                    DEF: Zproj_results
called by clam routine that creates results
projwin calls proj_results/
**********************************************************/
void Zproj_results(int type)
{
   resulttype = type;
   displaytype=Results;
   projwin(1);
}
/**********************************************************
                    DEF: Zproj_show_position
called by clam routine that orders contigs
**********************************************************/
void Zproj_show_position()
{
   if (!Zbatch_flag) {
     displaytype=ByPos;
     projwin(1);
   }
}
/***********************************************************88
                    DEF: updateproj
called when contigs are created or destroyed
************************************************************/
void updateproj()
{
int save=numPL, n, c;

   for (n=0; n<= max_contig; n++) // this is a kludge cause seq field not getting updated
   {
      if (contigs[n].count == 0) continue;
      contigs[n].seq=0;
      for (c = contigs[n].start; c!=-1; c =  arrp(acedata, c, CLONE)->next)
         if (arrp(acedata, c, CLONE)->seqstat != 0) contigs[n].seq++; 
   }
   if (graphExists(gtextwhole)) {
      nopop=1;
      compute_PL();
      if (save != numPL) {
         startline=0; projpage=0.0; highline=-1; 
      }
      projwin(0); 
      nopop=0;
   }
}
/***********************************************************
                    DEF: displayProj
called when project selected on main menu, and internally.
***********************************************************/
void displayProj()
{
   projwin(1);
}
/***********************************************************
                    DEF: optcallback
************************************************************/
static void optcallback()
{
   displaytype++;
   if (displaytype>=NOPTIONS) displaytype=0;
   projwin(1);
}
/***********************************************************
                    DEF: ctgcallback
************************************************************/
static void ctgcallback()
{
   CtgMsgFlag++;
   if (CtgMsgFlag>=3) CtgMsgFlag=0;
   projwin(1);
}
/***********************************************************
                    DEF: gotoHigh
***********************************************************/
static void gotoHigh()
{
int i;
float x;

    for (highline=-1, i=0; i<numPL && highline==-1; i++) {
      if (displaytype<=Results && PL[i].index == currentctg)
        highline=i;
      else if (PL[i].index == markerdisplayed)
        highline=i;
    }
    if (highline!=-1) {
      x =  highline / numlines;
      projpage = (int) x;
      if (x - projpage  > 0.5) projpage += 0.5; 
      startline = projpage * numlines;
      projwin(0);
    }
}
/***********************************************************
                    DEF: gotoTop
***********************************************************/
static void gotoTop()
{
    startline=0;
    projpage = 0.0;
    projwin(0);
}
/********************************************
                DEF: pickctg
********************************************/
static void pickctg(int box, double x, double y)
{
 int i;

 if(box <= 0 ) return;
 if(!graphActivate(gtextwhole)) return;
 if (scrollpicked(box, x, y)) return;
 for (i=0; i < numPL; i++){
       if (PL[i].box != box) continue;

       if(i == highline){
          if(currentctg != PL[i].index || ctg_window==NULL){
             newctg= TRUE;
             ctgdisplay(PL[i].index);
          }
          if(ctg_window!=NULL) gdk_window_raise(ctg_window->window);
       }
       else{
          if(highline > -1 && PL[highline].box !=0)
            graphBoxDraw(PL[highline].box,BLACK,WHITE);
          highline = i;
          graphBoxDraw(PL[i].box,WHITE,BLACK);
       }
       ZupdateProj(PL[highline].index);
       return;
  }
}
/**********************************************************
                    DEF: pickmark
used by both proj_ends and proj_framework
**********************************************************/
static void pickmark(int box, double x, double y)
{
int i;

  if (scrollpicked(box, x, y)) return;
  for (i=0; i< numPL; i++)
  {
       if (PL[i].box != box) continue;

       if (highline == i) {
          displaymarker(PL[i].index);
          graphPop();
       }
       else {
          if(highline > -1 && PL[highline].box !=0)
              graphBoxDraw(PL[highline].box,BLACK,WHITE);
          highline = i;
          graphBoxDraw(PL[i].box,WHITE,BLACK);
       }
       return;
  }
}
/***********************************************************
                     DEF: doline
*********************************************************/
static void doline(int i, int n, int n2, int format, char *msg)
{
char  str1[1000], c[20], m[20], s[20], d[20];
int j;

   if (numPL >= maxPL-1) {
     if (maxPL==0) {
         maxPL=1000;
         PL = (struct Proj_line *) calloc(sizeof(struct Proj_line), maxPL);
     }
     else {
         maxPL+=500;
         PL = (struct Proj_line *) realloc(PL, sizeof(struct Proj_line)*maxPL);
     }
   }
   j = numPL;
   numPL++;
   PL[j].n = n;
   PL[j].n2 = n2;
   PL[j].index = i;
   PL[j].draft = contigs[i].draft;
   PL[j+1].index = -1;

   if (format==2) { /* marker data */
      strncpy(PL[j].msg, msg, MSGSIZE*2);
      return;
   }
   sprintf(c,"%5d",contigs[i].count);    

   if(contigs[i].markers != 0) sprintf(m,"%5d",contigs[i].markers);
   else strcpy(m,"    -");

   if(contigs[i].seq != 0) sprintf(s,"%3d", contigs[i].seq);
   else strcpy(s,"  -");

   if(contigs[i].draft != 0) sprintf(d,"%3d", contigs[i].draft);
   else strcpy(d,"  -");

   sprintf(str1, " %s %s  %s  %s  %s",c,m,s,d,msg);
   strncpy(PL[j].msg, str1, MSGSIZE*2);
}
/*********************************************************************
                DEF: sortPL
**********************************************************************/
static int sortPL(const void *orig_a, const void *orig_b)
{
  struct Proj_line *a;
  struct Proj_line *b;
  
  a = (struct Proj_line*)orig_a;
  b = (struct Proj_line*)orig_b;

    if (PLsort == 3)
    {
        if (a->draft > b->draft) return -1;
        if (a->draft < b->draft) return 1;
    }
    if (a->n > b->n) return -1;
    if (a->n < b->n) return 1;
    if (PLsort == 1) {
      if (a->n2 > b->n2) return -1;
      if (a->n2 < b->n2) return 1;
    }
    if (a->index < b->index) return -1;
    if (a->index > b->index) return 1;
    return 0;
}
/*********************************************************************
             pageing routines
********************************************************************/
static void projdrag(float *x, float *y, BOOL isUP)
{
  int w,h;
  float num, pagebefore;

  *x = 0.5; /* or user can move bar horizontally; */
  if(!isUP) return;

  pagebefore = projpage;
  graphFitBounds(&w,&h);
  *y -= projtop; /* take away top bit*/
  h -= (projtop + 2.0);
  num = (*y/(float)h) * (float)(projmaxpage+1);
  projpage= (int)num;
  if (num - projpage > 0.5) projpage += 0.5; 

  if((*y < (projboxstart-projtop)) && projpage == pagebefore && projpage != 0)
      projpage-= 0.5;
  else if((*y > (projboxstart-projtop)) && projpage == pagebefore && projpage != projmaxpage)
      projpage += 0.5;

  if (projpage < 0.0) projpage = 0.0; 
  if (projpage > projmaxpage) projpage = projmaxpage; 

  startline = (int) (projpage * numlines);
  projwin(0);
}

static int scrollpicked(int box, double x, double y)
{
  if(!box) return 0;

  if(box==projbar){
      if(projmaxpage != 0)
        graphBoxDrag(box, projdrag);
      return 1;
  }
  if (box==projupkey){
      if (projpage > 0.0) {
        startline -= pagesize;
        projpage -= 0.5;
        projwin(0);
      }
      return 1;
  }
  if(box==projdownkey){
      if (projpage < projmaxpage) {
        startline += pagesize;
        projpage += 0.5;
        projwin(0);
      }
      return 1;
  }
return 0;
}

void projresize()
{
  projwin(0);
}
static void zhelp()
{
  show_help("Project Window","project");
}
/***********************************************************
                    DEF: projwin
***********************************************************/
static void projwin(int new)
{
  static MENUOPT menu2[] = { 
	{ quitProj,"Close "},
    {  editHighCtg,    "Edit Highlighted Contig"}, 
    {  gotoHigh,   "GoTo Current Contig"}, 
    {  gotoTop,    "GoTo Top"}, 
    {  printProj, "Print to file"}, 
    {  graphPrint, "Print Screen"}, 
    {  0, 0} } ;
  char str1[200], ctg[50];
  float line = 0.5;
  int w, h,  options, ctgMsg;
  int  i, j;
  float xpt,top,bottom,boxend;

  if (max_contig==0 || getcontigsmax()==0) {
      printf("No contigs to display in project window.\n");
      quitProj();
      return;
  }
  if (new) {
           /* init here instead of compute_PL so not done on updateproj */
      projpage=0.0;
      startline=0;
      highline = -1;
      compute_PL();
  }
  sprintf(str1,"Project %s ", fileName);
  if(graphActivate(gtextwhole)){
      graphClear();
      if (!nopop) graphPop();
  }
  else{                                /* x, y, w, h */    
      projpage=0.0;
      startline=0;
      highline = -1;
      gtextwhole = graphCreate (TEXT_FIT,str1,.6,.6,.70,.38) ;
      graphMenu (menu2) ;
  }
  options = graphButton(optlabel[displaytype],optcallback, 62.0, 0.2);
  graphBoxMenu(options, projmenu);
  graphButton("Help",zhelp, 74.0, 0.2);

  ctgMsg = graphButton(chrlabel[CtgMsgFlag],ctgcallback, 62.0, 1.5);
  graphBoxMenu(ctgMsg, ctgMsgmenu);

  graphRegister(RESIZE,projresize);
  graphButton("Search",ZeditProj, 62.0, 2.7);
  graphButton("Summary",Zsummary, 70.0, 2.7);

  if (numPL==0) {
     graphText(Proj.msg2[1],2.0,2.0);
     graphRedraw();
     return;
  }
/* scroll stuff */
  graphFitBounds(&w,&h);

  top = projtop;
  numlines = h - top;
  bottom = (float)h -2.0;
  projrange = (float)h - 2.0 - top;
  pagesize = numlines/2;
  if (numlines!=0) i = numPL/numlines; /* cari 21.6.4 */
  else i = 1;
  projmaxpage = i;
  if ((float)numPL/(float)numlines - (float)i > 0.5) projmaxpage+=0.5;
  
  sprintf(str1,"Project %s   Page %.1f of %.1f", 
         fileName, projpage+1.0, projmaxpage+1.0);
  graphRetitle(str1);

  projboxstart = ((projpage/(projmaxpage+1.0))*projrange) + top;
  boxend = (((projpage+1.0)/(projmaxpage+1.0))*projrange) + top;
  if (boxend > bottom) boxend = bottom;
  
  if((boxend - projboxstart) < 0.4) {
      if (projpage == projmaxpage) projboxstart=boxend - 0.4;
      else boxend = projboxstart + 0.4;
  }
  projbottom = bottom;

  xpt = 1.0;
  graphLine(xpt,top,xpt,bottom);

  projbar = graphBoxStart();
  graphRectangle(xpt-0.5,projboxstart,xpt+0.5,boxend);
  graphBoxEnd();
  graphBoxDraw(projbar,BLACK,GREEN);

  projupkey = graphBoxStart();
  graphRectangle(xpt-0.5,top,xpt+0.5,top-1.0);
  graphLine(xpt-0.5,top,xpt,top-1.0);
  graphLine(xpt,top-1.0,xpt+0.5,top);
  graphBoxEnd();
  graphBoxDraw(projupkey,BLACK,GREEN);

  projdownkey = graphBoxStart();
  graphRectangle(xpt-0.5,bottom,xpt+0.5,bottom+1.0);
  graphLine(xpt-0.5,bottom,xpt,bottom+1.0);
  graphLine(xpt,bottom+1.0,xpt+0.5,bottom);
  graphBoxEnd();
  graphBoxDraw(projdownkey,BLACK,GREEN);

/** Draw all lines on Proj window **/

  xpt = 2.0;
  graphText(Proj.msg2[2],xpt,line);
  line += 1.0; graphText(Proj.msg2[0],xpt,line);
  line += 1.0; graphText(Proj.msg2[1],xpt,line);
  line += 2.0; graphText(Proj.msg2[3],xpt,line);
  line += 1.0;

  for (i=0; i<numPL; i++)  PL[i].box = 0;

  if (numPL==0) {
       /* do nothing */
  }
  else if (displaytype <= Results) {
     graphRegister(PICK, pickctg);
     for (i=startline; i<startline+numlines && PL[i].index!=-1; i++) {
        sprintf(ctg,"%5d",PL[i].index);

        PL[i].box = graphBoxStart();
          j = graphTextFormat(BOLD);
          graphText(ctg,xpt,line);
          j = graphTextFormat(j);
          graphText(PL[i].msg,6.0+xpt,line);
        graphBoxEnd();

        if(highline == i)
           graphBoxDraw(PL[i].box,WHITE,BLACK);
        line += 1.0;
     }
  }
  else {
     graphRegister(PICK, pickmark);
     for (i=startline; i<startline+numlines && PL[i].index!=-1; i++) {
        sprintf(ctg,"%14s",arr(markerdata, PL[i].index, MARKER).marker);

        PL[i].box = graphBoxStart();
          j = graphTextFormat(BOLD);
          graphText(ctg,xpt,line);
          j = graphTextFormat(j);
          graphText(PL[i].msg,15.0+xpt,line);
        graphBoxEnd();

        if(highline == i)
           graphBoxDraw(PL[i].box,WHITE,BLACK);
        line += 1.0;
     }
  }
  graphRedraw();
}
/******************************************************************
                       DEF: compute_PL
*******************************************************************/
static void compute_PL()
{
int i;
int totalmark = 0,totalseq = 0;

  Proj.msg2[0][0]=Proj.msg2[1][0]='\0';
  numPL=0;
  for(i=0;i<=max_contig;i++){
    totalmark += contigs[i].markers;
    totalseq += contigs[i].seq;
  }
  sprintf(Proj.msg2[2], "FPC %s Clones %d Seq %d Markers %d",
        fileName,arrayMax(acedata), totalseq,arrayMax(markerdata));

  if (displaytype==FW) {
     proj_framework();
  }
  else if (displaytype==End) {
     strcpy(Proj.msg2[3],"     Marker      Ctg   Pos: Other contigs");
     proj_ends();
  }
  else if (displaytype==ByCtg) {
     sprintf(Proj.msg2[3],
        "Contig Clone Marker Seq  Draft       Date     Status   Qs  %s",chrlabel[CtgMsgFlag]);
     By_ctg();
  }
  else if (displaytype==ByPos) {
     sprintf(Proj.msg2[3],
        "Contig Clone Marker Seq  Draft  Position Edit %s",chrlabel[CtgMsgFlag]);
     By_pos();
  }
  else if (displaytype==ByLen) {
     sprintf(Proj.msg2[3],
        "Contig Clone Marker Seq  Draft       Date     Status   Qs  %s",chrlabel[CtgMsgFlag]);
     By_len();
  }
  else if (displaytype==ByClones) {
     sprintf(Proj.msg2[3],
        "Contig Clone Marker Seq  Draft       Date     Status   Qs  %s",chrlabel[CtgMsgFlag]);
     By_size();
  }
  else if (displaytype==ByCounts) {
     strcpy(Proj.msg2[3],"Contig Clone Marker Seq  Draft  Buried Type");
     proj_counts();
  }
  else if (displaytype==BySeq) {
     strcpy(Proj.msg2[3],
        "Contig Clone Marker Seq  Draft   SD Til Sen Rea Sho Fin  Auto Ful Haf Gap");
     proj_seq();
  }
  else if (displaytype==ByDraft) {
     sprintf(Proj.msg2[3],
        "Contig Clone Marker Seq  Draft       Date     Status   Qs  %s",chrlabel[CtgMsgFlag]);
     By_draft();
  }
  else if (displaytype==ByKey) {
     sprintf(Proj.msg2[3],
        "Contig Clone Marker Seq Draft  By KeySet  %s",chrlabel[CtgMsgFlag]);
     proj_keyset();
  }
  else if (displaytype==Results) {
     if (resulttype==0)  /* c2am and default */      
        strcpy(Proj.msg2[3],"Contig Clone Marker Seq  Draft   Qs    Results");
     else if (resulttype==1) /* ibc */ 
        strcpy(Proj.msg2[3],"Contig Clone Marker Seq  Draft   Qs   Add Merge");
     else if (resulttype==2) /* Build contigs */ 
        strcpy(Proj.msg2[3],"Contig Clone Marker Seq  Draft  Qs   Score    Avg    Low");
     else if (resulttype==3) /* editproj */ 
        strcpy(Proj.msg2[3],"Contig Clone Marker Seq  Draft  Results");
     proj_results();
  }
  else if (displaytype==ByScore) {
     sprintf(Proj.msg2[3],
        "Contig Clone Marker Seq  Draft  Score    Avg    Low    Qs  %s",chrlabel[CtgMsgFlag]);
     By_score();
  }
  if (PLsort)
        qsort(PL, numPL, sizeof(struct Proj_line), sortPL);
}
/*****************************************************************
                        DEF: do_msg
******************************************************************/
static void do_Msg(int i)
{
char q[20], buf[20], tmpmsg[CTGMSG_SZ];
void formatdate();

    formatdate(&(contigs[i].ctgdate), buf);
    if (contigs[i].ctgQs == -1) sprintf(q, "  -");
    else if (contigs[i].approxQs) sprintf(q,"~%2d", contigs[i].ctgQs);
    else sprintf(q," %2d", contigs[i].ctgQs);

    if (CtgMsgFlag==0) strncpy(tmpmsg,contigs[i].chr_msg,CTGMSG_SZ);
    else if (CtgMsgFlag==1) strncpy(tmpmsg,contigs[i].user_msg,CTGMSG_SZ);
    else strncpy(tmpmsg,contigs[i].trace_msg,CTGMSG_SZ);

    sprintf(Msg,"%s %4s%c   %s  %s", buf,
       ctgstat[contigs[i].ctgstat], contigs[i].ctgIBC, q, tmpmsg);
}
/********************************************************************
                        By_ctg
********************************************************************/
static void By_ctg()
{
int i,c;

   PLsort=0;
   for (c=i=0; i<=max_contig; i++) 
     if (contigs[i].count!=0) {
        do_Msg(i);
        doline(i,i,0,0,Msg);
        if (i!=0) c++;
     }
  sprintf(Proj.msg2[1],"Contigs %d  Max Contig %d ", c, getcontigsmax());
  getdatehead(Proj.msg2[0]);
}
/********************************************************************
                        By_size
********************************************************************/
static void By_size()
{
int tot=0, max=0, bin[4];
int i;

  PLsort=1;
  bin[0]=bin[1]=bin[2]=bin[3]=0;
  for (i=1; i<= max_contig; i++)
  {
      if (contigs[i].count==0) continue;
      if (contigs[i].count > 25) bin[0]++;
      else if (contigs[i].count > 10) bin[1]++;
      else if (contigs[i].count > 2) bin[2]++;
      else bin[3]++;
      tot++;
      max = MaX(max, contigs[i].count);
      do_Msg(i);
      doline(i,contigs[i].count, 0, 0, Msg);
  }
  sprintf(Proj.msg2[0],
       "Contigs %d   Singles %d", tot, contigs[0].count);
  sprintf(Proj.msg2[1],
       "Max %d, %d (>25), %d (25:10), %d (9:3), %d (2)",
              max, bin[0], bin[1], bin[2], bin[3]);
}
/********************************************************************
                        By_draft
********************************************************************/
static void By_draft()
{
int i;

  PLsort=3;
  for (i=1; i<= max_contig; i++)
  {
      do_Msg(i);
      doline(i,contigs[i].count, 0, 0, Msg);
  }

}
/********************************************************************
                        By_pos
********************************************************************/
static void By_pos()
{
int tot=0;
int i;
char str1[2], str2[2], str3[10];

  PLsort=0;
  for (i=1; i<= max_contig; i++)
  {
      if (contigs[i].count==0) continue;
      if (contigs[i].chr_pos>0) tot++;
      str1[0]=str2[0]=' ';
      if (contigs[i].noedit_chr) str1[0] = 'C';
      if (contigs[i].noedit_pos) str2[0] = 'P'; 
      if (contigs[i].chr_pos < 0) strcpy(str3,"       ");
      else sprintf(str3,"%7.2f",contigs[i].chr_pos);
      sprintf(Msg,"%s   %c%c   %s",str3,
          str1[0],str2[0], contigs[i].chr_msg);
      doline(i,i, 0, 0, Msg);
  }
  sprintf(Proj.msg2[0], "Positioned contigs %d", tot);
}
/***************************************************************
                    DEF: proj_counts
***************************************************************/
static void proj_counts()
{
CLONE *clp;
int k, b=0, found, i, j;
char letter, tmp[20], line[1000];
struct cnts {
   char set[26];
   int cnt[26];
   int b;
   int max;
} *ctg;

  PLsort=1;
  ctg = (struct cnts *) calloc(sizeof(struct cnts), max_contig+1);
  NOMEM2(ctg, "ctg");

  for (i=0; i <=max_contig; i++) 
      for (j=0; j <= 26; j++) 
          ctg[i].cnt[j] = ctg[i].b = ctg[i].max = 0;

  for (i=0; i < arrayMax(acedata); i++) 
  {
      clp = arrp(acedata, i, CLONE);
      k = clp->ctg;
      letter = clp->clone[0];
      for (found=j=0; j<ctg[k].max && found==0; j++) 
          if (letter == ctg[k].set[j]) {
             ctg[k].cnt[j]++;
             found=1;
          }
      if (!found && ctg[k].max<26) {
          ctg[k].set[ctg[k].max]=letter;
          ctg[k].cnt[ctg[k].max]=1;
          ctg[k].max++;
      } 
      if (clp->match[0] != ' ') 
          ctg[k].b++;
  }

  for (b=i=0; i <= max_contig; i++) 
  {
       if (contigs[i].count == 0)  continue;
       b =+ ctg[i].b;
       sprintf(line, "Buried %d ", ctg[i].b);
       for (j=0; j<26; j++) {
         if (ctg[i].cnt[j] > 0) {
            sprintf(tmp, "%c%d ",ctg[i].set[j],ctg[i].cnt[j]);
            strcat(line, tmp);
         }
       }
       strncpy(Msg,line,50);
       doline(i, contigs[i].count,0,0,Msg);
  }
  sprintf(Proj.msg2[0],"Contig: buried %-5d ", b);
  sprintf(Proj.msg2[1]," ");
  free(ctg);
}
/**********************************************************
                    DEF: By_len
**********************************************************/
static void By_len()
{
CLONE *clp;
struct markertop *mkptr;
struct marker *marker;
int i,j, k, n, size, totlen, cnt;
int x, ctgbands;
char qs[5], remark[CTGMSG_SZ];
int found, cnt_anchor[1000], max;

  PLsort=1;
  cnt=totlen=0;
  size = Proj.avgbandsize;
  for (i=1; i<= max_contig; i++)
  {
      if (contigs[i].count == 0) continue;
      if (contigs[i].ctgstat == DEAD) continue;

      if (CtgMsgFlag==0) strcpy(remark, contigs[i].chr_msg);
      else if (CtgMsgFlag==1) strcpy(remark, contigs[i].user_msg);
      else strcpy(remark, contigs[i].trace_msg);
      for (k=0; k<1000; k++) cnt_anchor[k]=0;
      max=0;
            /* cnt number of anchors */
      for (j=contigs[i].start; j != -1; j = clp->next)
      {
           clp = arrp(acedata,j,CLONE);
           for (mkptr = clp->marker; mkptr != NULL; mkptr=mkptr->nextmarker)
           {
               marker = arrp(markerdata, mkptr->markerindex, MARKER);
               if (marker->anchor==FALSE) continue;
               for (found=0, k=0; k<max && !found; k++) 
                   if (cnt_anchor[k]==mkptr->markerindex) found=1;
               if (!found) {
                   cnt_anchor[max]=mkptr->markerindex;
                   max++;
               }
           }
      }
      cnt++;
      ctgbands = (contigs[i].right - contigs[i].left+1);
      n = (ctgbands * size)/1000;
      totlen+=n;
      if (contigs[i].ctgQs == -1) strcpy(qs,"  -");
      else if (contigs[i].approxQs) sprintf(qs,"~%2d",contigs[i].ctgQs);
      else sprintf(qs," %2d",contigs[i].ctgQs);
      sprintf(Msg,"%5d %5d %5d   %5s  %s",n,ctgbands, max, qs, remark);
      doline(i, n, 0,0, Msg);
  }
  x = (cnt > 0) ? totlen/cnt : 0; /* BUG: 1/17/2 CAS */
  sprintf(Proj.msg2[1],"TotalLen %d kb AvgLen %d kb", totlen, x);
  getdatehead(Proj.msg2[0]);
}
/**********************************************************
                    DEF: proj_seq
If something is changed here, also change in summary.c
**********************************************************/
static void proj_seq()
{
CLONE *clp;
int status[10], ts[10], type[10], tt[10];
int c, i, n, cnt;
char  cs[10][5], ct[10][5];

  PLsort=1;
  for (i=0; i<10; i++) 
     ts[i]=tt[i]=0;

  for (n=0; n<= max_contig; n++)
  {
      if (contigs[n].count == 0) continue;
      for (i=0; i<10; i++) 
          type[i]=status[i]=0;
      cnt=0;
      for (c = contigs[n].start; c!=-1; c =  clp->next)
      {
         clp =  arrp(acedata, c, CLONE); 
         if (clp->seqstat!=0) {
            cnt++;
            if (clp->seqstat==TILE) status[0]++;
            else if (clp->seqstat==SENT) status[1]++;
            else if (clp->seqstat==READY) status[2]++;
            else if (clp->seqstat==SHOTGUN) status[3]++;
            else if (clp->seqstat==FINISHED) status[4]++;
            else if (clp->seqstat==CANCELLED) status[5]++;
            else if (clp->seqstat==SD) status[6]++;
         }
         if (clp->seqtype!=0) {
            if (clp->seqtype==FULLX) type[0]++;
            else if (clp->seqtype==HALFX) type[1]++;
            else if (clp->seqtype==GAPCLOSURE) type[2]++;
            else if (clp->seqtype==AUTOMATIC) type[3]++;
         }
      } 
      if (cnt == 0) Msg[0]='\0';
      else {
        for (i=0; i<4; i++)
           if (type[i] > 0) sprintf(ct[i], "%3d", type[i]);
           else strcpy(ct[i],"  -");
        for (i=0; i<8; i++)
           if (status[i] > 0) sprintf(cs[i], "%3d", status[i]);
           else strcpy(cs[i],"  -");
        for (i=0; i<4; i++) tt[i]+=type[i];
        for (i=0; i<8; i++) ts[i]+=status[i];
              
        sprintf(Msg,"%s %s %s %s %s %s  %s %s %s %s",
             cs[6], cs[0], cs[1], cs[2], cs[3], cs[4], ct[3], ct[0], ct[1], ct[2]);
      }
      if (status[5]>0) doline(n, contigs[n].seq,1, 1, Msg);
      else doline(n, contigs[n].seq, 0, 1, Msg);
  }
  sprintf(Proj.msg2[0],
   "Tile %d Submit %d Ready %d Shotgun %d Finish %d SD %d",  
           ts[0], ts[1], ts[2], ts[3], ts[4], ts[6]);
  sprintf(Proj.msg2[1], 
   "Full-X %d Half-X %d Gap %d   Automatic %d", 
           tt[0], tt[1], tt[2], ts[3]);
}
/**********************************************************
                    DEF: proj_keyset
**********************************************************/
static void proj_keyset()
{
CLONE *clp;
struct list *lp;
int i;
int cnt=0, *ctg;
char tmp[CTGMSG_SZ];
void keyset_results();
struct seqctgpos* ctgpos;

  if (classctg == CLONECLASS && graphExists(g2)) {
     PLsort=1;
     ctg = (int *) calloc(sizeof(int), max_contig+1);
     for (i=0; i<=max_contig; i++) ctg[i]=0;

     for (lp = listroot; lp!=NULL; lp = lp->next) 
     {
        clp = arrp(acedata,lp->index,CLONE);
        ctg[clp->ctg]++;
     }
     for (i=1; i<=max_contig; i++) {
         if (contigs[i].count==0) continue;

         if (CtgMsgFlag==0) strcpy(tmp, contigs[i].chr_msg);
         else if (CtgMsgFlag==1) strcpy(tmp, contigs[i].user_msg);
         else strcpy(tmp, contigs[i].trace_msg);

         if (ctg[i]>0) {
            cnt++; 
            sprintf(Msg,"  %4d     %s",ctg[i], tmp);
         }
         else  {
            sprintf(Msg,"          %s", tmp);
         }
         doline(i, ctg[i], 0, 0, Msg); 
     }
     free(ctg);
     sprintf(Proj.msg2[1],"Contigs with clones in keyset %d ", cnt);
  }
  else if (classctg == SEQCLASS && graphExists(g2)) {
     PLsort=1;
     ctg = (int *) calloc(sizeof(int), max_contig+1);
     for (i=0; i<=max_contig; i++) ctg[i]=0;

     for (lp = listroot; lp!=NULL; lp = lp->next) 
     {        
        for (ctgpos = lp->seq->ctgpos; ctgpos != 0; ctgpos = ctgpos->next)
        {
            ctg[ctgpos->ctg]++;
        }        
     }
     for (i=1; i<=max_contig; i++) {
         if (contigs[i].count==0) continue;

         if (CtgMsgFlag==0) strcpy(tmp, contigs[i].chr_msg);
         else if (CtgMsgFlag==1) strcpy(tmp, contigs[i].user_msg);
         else strcpy(tmp, contigs[i].trace_msg);

         if (ctg[i]>0) {
            cnt++; 
            sprintf(Msg,"  %4d     %s",ctg[i], tmp);
         }
         else  {
            sprintf(Msg,"          %s", tmp);
         }
         doline(i, ctg[i], 0, 0, Msg); 
     }
     free(ctg);
     sprintf(Proj.msg2[1],"Contigs with sequences in keyset %d ", cnt);
  }
  else if (classctg == MARKERCLASS && graphExists(g2)) {
     keyset_results();
  }
  else {
     PLsort=0;
     for (i=0; i<max_contig; i++)
       if (contigs[i].count!=0) doline(i,i,0,0," ");

     sprintf(Proj.msg2[1],"No Keyset");
  }
  getdatehead(Proj.msg2[0]);
}
/**********************************************************
                    DEF:proj_results
**********************************************************/
static void proj_results()
{
int i;
int cnt=0;
char status[20];

   PLsort=2;
   for (i=1; i<=max_contig; i++) {
     if (contigs[i].count==0) continue;
     if (contigs[i].ctgstat < 0 || contigs[i].ctgstat >= ctgstatnum) {
        printf("Incorrect status %d for ctg %d\n",contigs[i].ctgstat, i);
        contigs[i].ctgstat = 0;
     }
     if (contigs[i].ctgQs==-1) strcpy(status,"  -");
     else if (contigs[i].approxQs) sprintf(status,"~%2d",contigs[i].ctgQs);
     else sprintf(status," %2d",contigs[i].ctgQs);

     if (contigs[i].projmsg[0]=='\0') {
         if (resulttype==3) doline(i,0, i, 0, "\0");
         else doline(i,0, i, 0, status);
     }
     else {
         cnt++;
         if (resulttype<=1) { /* IBC = 1 Ends2Ends = 0 */
            sprintf(Msg,"%-5s  %s", status, contigs[i].projmsg);
            doline(i, 1 , i, 0, Msg);
         }
         else doline(i, 1 , i, 0, contigs[i].projmsg);
     }
   }
  if (cnt==0) PLsort=0;
  sprintf(Proj.msg2[1],"Contigs with results %d  Tolerance %d cutoff %.0e ", 
           cnt, Pz.tol, Pz.cutFlt);
  getdatehead(Proj.msg2[0]);
}
/********************************************************************
                        By_score
********************************************************************/
static void By_score()
{
int tot=0;
int i, score;
char q[5], tmpmsg[CTGMSG_SZ];

  PLsort=1;
  for (i=1; i<= max_contig; i++)
  {
      if (contigs[i].count==0) continue;
      tot++;
      
      if (contigs[i].ctgQs == -1) sprintf(q, "  -");
      else if (contigs[i].approxQs) sprintf(q,"~%2d", contigs[i].ctgQs);
      else sprintf(q," %2d", contigs[i].ctgQs);

      if (CtgMsgFlag==0) strncpy(tmpmsg,contigs[i].chr_msg,CTGMSG_SZ);
      else if (CtgMsgFlag==1) strncpy(tmpmsg,contigs[i].user_msg,CTGMSG_SZ);
      else strncpy(tmpmsg,contigs[i].trace_msg,CTGMSG_SZ);
      score = 1000 - (contigs[i].low_score);
      sprintf(Msg,"%-6.3f %-6.3f %-6.3f %4s  %s", 
               (float) contigs[i].high_score/1000.0, (float)contigs[i].avg_score/1000.0, 
               (float)contigs[i].low_score/1000.0, q, tmpmsg);
        /* cari 3sept4 - sorts on the 2nd doline parameter, which is integer */
      doline(i,score, 0, 0, Msg);
  }
}

/**********************************************************
                    DEF: proj_ends
**********************************************************/
static void proj_ends()
{
int i, j,  index;
struct marker *marker;
struct markerctgpos *ptr;
struct markerclone *mclp;
char  str[200], x[20];
int  noparent=0, cnt=0, mainctg, mainpos;

  PLsort=1;
  getdatehead(Proj.msg2[0]);

  for (j=i=0; i<arrayMax(markerdata); i++) {
      mainctg= -1; mainpos=0;
      marker = arrp(markerdata, i, MARKER);

      index = marker->cloneindex;
      mclp = marker->nextclone;
      do{
           if (strstr(marker->marker,
                 arrp(acedata, index, CLONE)->clone) != NULL)
           {
               mainctg=arrp(acedata, index, CLONE)->ctg;
               break;
           }
           if (mclp==NULL) break;
           index = mclp->cloneindex;
           mclp = mclp->nextclone;
      } while (1);

      if (mainctg==-1 && marker->type!=markEND) continue;
      if (mainctg==-1 && marker->type==markEND) noparent++;
      str[0]='\0';
      for (ptr = marker->pos; ptr!=NULL; ptr=ptr->next)
      {
           if (mainctg!= ptr->ctg) {
              sprintf(x,"%d ",ptr->ctg);
              if (strlen(str) < MSGSIZE) strcat(str,x); /* CHG 03/08/01 */
           }
           else mainpos = ptr->pos;
      }
      if (mainctg!=-1) {
         sprintf(Msg,"%5d %5d: %s",mainctg, mainpos, str);
         doline(i,mainctg,mainpos,2,Msg);
      }
      else {
         sprintf(Msg,"           : %s", str);
         doline(i,99999,0,2,Msg);
      }
      cnt++;
  }
  sprintf(Proj.msg2[1], "Ends sequences %d",cnt);
}
/**********************************************************
                    DEF: proj_framework
**********************************************************/
static void proj_framework()
{
int i, j, k,  c;
float line=1.5;
struct marker *marker;
struct markerclone *mclp;
struct markerctgpos *ptr;
char  f, str[200], seq[5];
int ctg, fwcnt=0, placecnt=0, diff;
void Zget_framework();
int tmppos, tmpcnt, lastpos=-999999, lastctg=-1, tmpctg;
int getChrForMarker();

  PLsort=0;
  getdatehead(Proj.msg2[0]);
  if (Proj.mapname[0]=='\0') {
       strcpy(Proj.msg2[1],"No framework markers");
       return;
  }
  Zget_framework();
  if (FWcnt==0) {
       strcpy(Proj.msg2[1],"No framework markers");
       free(FWmarks); 
       return;
  }
  if (Proj.label_abbrev[0]!='\0') {
    if (chrtype==1) sprintf(Proj.msg2[3],
        "     Marker       %-2s", Proj.label_abbrev);
    else if (chrtype==1) sprintf(Proj.msg2[3],
        "     Marker       %-3s  ", Proj.label_abbrev);
    else sprintf(Proj.msg2[3],
        "     Marker       %-3s     ", Proj.label_abbrev);
    strcat(Proj.msg2[3],"     Diff Seq  Pos  Ctg/NumberClones");
  }
  else strcpy(Proj.msg2[3],
        "     Marker         Diff Seq  Pos  Ctg/NumberClones");

  for (i=0; i<FWcnt; i++) {
      marker = arrp(markerdata, FWmarks[i].index, MARKER);

      if (marker->frame_type == FRAME) {f = 'F'; fwcnt++;}
      else {f = ' '; placecnt++;}

      if (i!=0 && FWmarks[i].anchor_bin[0] == FWmarks[i-1].anchor_bin[0]) 
           diff = (FWmarks[i].pos - FWmarks[i-1].pos);
      else diff=-1;

      strcpy(seq," ");

      /*fred 8/20/03 -- for first clone...*/
      ctg = arrp(acedata, marker->cloneindex, CLONE)->ctg;
      for (j=0; FWmarks[i].ctg[j] != -1 && 
           FWmarks[i].ctg[j] != ctg; j++);
      if (FWmarks[i].ctg[j]!= -1) FWmarks[i].cnt[j]++;
      if (IsSeq(arrp(acedata,marker->cloneindex,CLONE))) strcpy(seq,"S");

      /* ... for additional clones*/
      for (mclp = marker->nextclone; mclp!=NULL; mclp = mclp->nextclone)
      {
           ctg = arrp(acedata, mclp->cloneindex, CLONE)->ctg;
           for (j=0; FWmarks[i].ctg[j] != -1 && 
                     FWmarks[i].ctg[j] != ctg; j++);
           if (FWmarks[i].ctg[j]!= -1) FWmarks[i].cnt[j]++;
           
           if (IsSeq(arrp(acedata,mclp->cloneindex,CLONE))) strcpy(seq,"S");
      } 

      line++;
      if (diff == -1) sprintf(str, "      %s  ",seq);
      else sprintf(str, " %4d %s  ",diff, seq);

     if (Proj.label_abbrev[0]!='\0'){
        if (chrtype==0) 
            sprintf(Msg,"%c  %-2s %s",f, FWmarks[i].anchor_bin, str);
        else if (chrtype==1) 
            sprintf(Msg,"%c  %-5s %s",f, FWmarks[i].anchor_bin, str);
        else  
            sprintf(Msg,"%c  %-8s %s",f, FWmarks[i].anchor_bin, str);
      }
      else sprintf(Msg,"%c %s",f, str);

                /* sort contigs by number of clones */
      for (k=0; FWmarks[i].cnt[k]!=0; k++) 
         for (j=k+1; FWmarks[i].cnt[j]!=0; j++) {
             if (FWmarks[i].cnt[k] < FWmarks[i].cnt[j]) {
                tmpcnt = FWmarks[i].cnt[k];
                tmpctg = FWmarks[i].ctg[k];
                FWmarks[i].cnt[k] = FWmarks[i].cnt[j];
                FWmarks[i].ctg[k] = FWmarks[i].ctg[j];
                FWmarks[i].cnt[j] = tmpcnt;
                FWmarks[i].ctg[j] = tmpctg;
             }
         }
     for (tmppos=k=0, ptr = marker->pos; ptr!=NULL; ptr=ptr->next)
         if (ptr->ctg == FWmarks[i].ctg[0]) {
             tmppos=ptr->pos;
             break;
         }
     
     if (FWmarks[i].ctg[0] == -1) FWmarks[i].ctg[0]=0;

     if (FWmarks[i].ctg[0]!=0 && FWmarks[i].ctg[0]==lastctg && i !=0) c = ' ';
     else c = '*';
     sprintf(str,"%5d%c %5d/%-2d ",tmppos, c, FWmarks[i].ctg[0], FWmarks[i].cnt[0]);

     strcat(Msg,str);
     lastpos = tmppos;
     lastctg = FWmarks[i].ctg[0];

     for (k=1; FWmarks[i].cnt[k]!=0; k++) {
        if (FWmarks[i].ctg[k] == -1) FWmarks[i].ctg[k]=0;
        sprintf(str," %d/%d",FWmarks[i].ctg[k], FWmarks[i].cnt[k]);
        strcat(Msg,str);
        if (strlen(Msg) > 100) break;
     }
     doline( FWmarks[i].index, 0,0,2,Msg);
  }
  if (fwcnt==0 && placecnt!=0)
     sprintf(Proj.msg2[1],"Frameworks %d ", placecnt); 
  else
     sprintf(Proj.msg2[1],"Frameworks %d Placed %d  Total %d",
        fwcnt, placecnt, fwcnt+placecnt); 
  free(FWmarks);
}

/*********************************************************************
                DEF: sortFW
Format:
 1q1.1,....Xq1.1, Yq1.1
 1q1,.....Xq1, Yq1
 1.1, ....X.1, Y.1
 1,..., X,Y
 A, B.....

**********************************************************************/
int chrPart(int a1, int b1, char ax, char bx)
{ 
/* 1, 2... X or Y */

    if (ax != ' ' && bx != ' ') {
        if (ax < bx) return -1;
        if (ax > bx) return 1;
        return 0;
    }
    if (ax == ' ' && bx != ' ') return 1;
    if (ax != ' ' && bx == ' ') return -1;
    if (a1==b1) return 0;
    if (a1==0)  return 1;
    if (b1==0)  return -1;
    if (a1 < b1) return -1;
    if (a1 > b1) return 1;
    return 0;
}
static int secondPart(char ac, char bc, int a2, int b2)
{ 
/* 1, 2... X or Y */
   if (ac < bc) return -1;
   if (ac > bc) return  1;
   if (a2 < b2) return -1;
   if (a2 > b2) return 1;
   return 0;
}
static int position(int apos, int bpos)
{ 
        if (apos < bpos) return -1;
        if (apos > bpos) return 1;
        return 0;
}


static int same_char_type(char a, char b)
{
    if (a != 0 && b != 0)
    {
        if (    (isalpha(a) && isalpha(b)) ||
                (isdigit(a) && isdigit(b)) )
        {
            return 1;
        }
    }
    return 0;
}

static void string_chop(char* sz, int* cut)
{
    assert(sz);
    assert(*sz); /* should not be fed an empty string */
    assert(cut);

    /* find the first location after type
         change, or end of string */

    for (*cut = 1; *cut <= strlen(sz) && same_char_type(sz[*cut],sz[*cut - 1]); (*cut)++);
 }

static int recursive_sort(char* sz1, char* sz2)
{
    char *p1, *p2, *_p1, *_p2;
    int ret = 0;
    int cut1, cut2;
    char c1, c2;
    int num1, num2;

    assert(sz1);
    assert(sz2);

    _p1 = strdup(sz1);
    _p2 = strdup(sz2);

    p1 = _p1;
    p2 = _p2;

    /* first skip any leading non-alphanum chars, like '.' */

    while (*p1 && !isalnum(*p1)) p1++;
    while (*p2 && !isalnum(*p2)) p2++;

    /* handle zero length cases first */

    if (strlen(p1) == 0)
    {
        return (strlen(p2) > 0 ? 1 : 0);
    }
    else if (strlen(p2) == 0)
    {
        return -1;
    }

    /* Pull out the leading fields, determined by either a letter/number change
        or a non-alphanumeric char */

    string_chop(p1,&cut1);
    string_chop(p2,&cut2);

    c1 = p1[cut1];
    c2 = p2[cut2];
    
    p1[cut1] = 0;
    p2[cut2] = 0;

    /* Now compare the leading fields */

    if (isdigit(*p1) && isdigit(*p2))
    {
        num1 = strtol(p1,0,10);
        num2 = strtol(p2,0,10);
        ret = (num1 > num2 ? 1 : (num2 > num1 ? -1 : 0) );   
    }    
    else
    {
        ret = strcmp(p1,p2);
    }

    if (ret == 0)
    {
        p1[cut1] = c1;
        p2[cut2] = c2;
        ret = recursive_sort(&p1[cut1],&p2[cut2]);
    }

    free(_p1);
    free(_p2);

    return ret;
}

/*********************************************************
                sortFW
its only necessary to wort on the chromosome or linkage 
group. the rest of this is probably not necessary as the 
genetic positions should be consecutive for a chromosome
or linkage group and consistent with p/q arm and banding
pattern.
********************************************************/

int sortFW_old(const void *orig_a, const void *orig_b)
{
  struct framework *a;
  struct framework *b;
  int val=0;
  int a1, a2, a3, b1, b2, b3;
  char ax, ac, bx, bc;

  a = (struct framework*)orig_a;
  b = (struct framework*)orig_b;

  chrtype=1;
          /* no anchor_bin, sort on position */
  if ((a->anchor_bin[0]=='\0') && (b->anchor_bin[0]=='\0')) 
       return position(a->pos, b->pos);

          /* 1q1.1, Xq1.1 */
  ax = bx = ' ';
  if ((sscanf(a->anchor_bin,"%d%c%d.%d",&a1,&ac,&a2,&a3)==4)  ||
       ((sscanf(a->anchor_bin,"%c%c%d.%d",&ax,&ac,&a2,&a3)==4) &&
        (ax == 'X' || ax == 'Y')))
  {
     if ((sscanf(b->anchor_bin,"%d%c%d.%d",&b1,&bc,&b2,&b3)==4)  ||
        ((sscanf(b->anchor_bin,"%c%c%d.%d",&bx,&bc,&b2,&b3)==4) &&
         (bx == 'X' || bx == 'Y')))
     {
           chrtype=3;
           if ((val = chrPart(a1,b1,ax,bx))!=0) return val;
           if ((val = secondPart(ac,bc,a2,b2))!=0) return val;
           if (a3 < b3) return -1;
           if (a3 > b3) return 1;
           return position(a->pos, b->pos);
     }
     else {
        printf("Inconsistent labels %s %s\n",a->anchor_bin,b->anchor_bin);
        return 0;
     }
  } 
        /* 1q1, Xq1, 1.1, X.1 */
  ax = bx = ' ';
  if ((sscanf(a->anchor_bin,"%d%c%d",&a1,&ac,&a2)==3)  ||
       ((sscanf(a->anchor_bin,"%c%c%d",&ax,&ac,&a2)==3) &&
        (ax == 'X' || ax == 'Y')))
  {
     if ((sscanf(b->anchor_bin,"%d%c%d",&b1,&bc,&b2)==3)  ||
       ((sscanf(b->anchor_bin,"%c%c%d",&bx,&bc,&b2)==3) &&
        (bx == 'X' || bx == 'Y')))
     {
           chrtype=3;
           if ((val = chrPart(a1,b1,ax,bx))!=0) return val;
           if ((val = secondPart(ac,bc,a2,b2))!=0) return val;
           return position(a->pos, b->pos);
     }
     else {
        printf("Inconsistent labels %s %s\n",a->anchor_bin,b->anchor_bin);
        return 0;
     }
  } 
        /* 1, 2, X, Y */
  ax = bx = ' ';
  if ((sscanf(a->anchor_bin,"%d",&a1)==1)  ||
       ((sscanf(a->anchor_bin,"%c",&ax)==1) &&
        (ax == 'X' || ax == 'Y')))
  {
     if ((sscanf(b->anchor_bin,"%d",&b1)==1)  ||
       ((sscanf(b->anchor_bin,"%c",&bx)==1) &&
        (bx == 'X' || bx == 'Y')))
     {
           if ((val = chrPart(a1,b1,ax,bx))!=0) return val;
           return position(a->pos, b->pos);
     }
     else {
        printf("Inconsistent labels %s %s\n",a->anchor_bin,b->anchor_bin);
        return 0;
     }
  }
          /* A.1, B.2, ... */
  if (sscanf(a->anchor_bin,"%c.%d",&ac,&a2)==2) 
  {
     if (sscanf(b->anchor_bin,"%c.%d",&bc,&b2)==2) 
     {
           chrtype=2;
           if ((val = secondPart(ac,bc,a2,b2))!=0) return val;
           return position(a->pos, b->pos);
     }
     else {
        printf("Inconsistent labels %s %s\n",a->anchor_bin,b->anchor_bin);
        return 0;
     }
  }
         /* A, B, ... */
  if ((val = strcmp(a->anchor_bin, b->anchor_bin))!=0) return val;
  return position(a->pos, b->pos);
}

/* WMN  
    For the old style names - calls the old routine
    For generic names - calls a new routine to go field by field */
static int sortFW(const void *orig_a, const void *orig_b)
{
  struct framework *a;
  struct framework *b;

  if (Proj.generic_grpnames == 0)
  {
     return sortFW_old(orig_a,orig_b);
  }

  a = (struct framework*)orig_a;
  b = (struct framework*)orig_b;

  /* no anchor_bin, sort on position */
  if ((a->anchor_bin[0]=='\0') && (b->anchor_bin[0]=='\0')) 
       return position(a->pos, b->pos);

  return recursive_sort(a->anchor_bin,b->anchor_bin);

}



/*********************************************************************
                DEF: Zget_framework
The framework structure is defined in file/proj.h
The file enters the info: name, index, position, and list of contigs.
It does not list how many clones are hit in each contig.
**********************************************************************/
void Zget_framework()
{
struct markerctgpos *ptr;
struct marker *marker;
int x=1000;
int k, i, j;

  FWmarks = (struct framework *) malloc(x * sizeof(struct framework));
  NOMEM2(FWmarks, "frameworks");

  for (j=i=0; i<arrayMax(markerdata); i++) {
      marker = arrp(markerdata, i, MARKER);
      if (!marker->anchor) continue;
      for (k=0, ptr = marker->pos; ptr!=NULL; ptr=ptr->next)
      {
         FWmarks[j].ctg[k] = ptr->ctg; 
         FWmarks[j].cnt[k] = 0; 
         k++;
         if (k==MAX_CTG_FW-1) {
            printf("Marker %s in more than %d contigs!!\n",marker->marker, MAX_CTG_FW-1);
            break;
         }
      }
      FWmarks[j].ctg[k] = -1; 
      FWmarks[j].cnt[k] = 0; 
      strcpy(FWmarks[j].name, marker->marker);

      FWmarks[j].pos = marker->anchor_pos;
      strcpy(FWmarks[j].anchor_bin,marker->anchor_bin);

      FWmarks[j].index = i;
      j++;
      if(j == x){ 
	x +=500;
        FWmarks = (struct framework *) realloc(FWmarks, x * sizeof(struct framework));
        NOMEM2(FWmarks, "framework marks");
      }
  }
  FWcnt = j;
  if (j==0) return;
  qsort(FWmarks, FWcnt, sizeof(struct framework), sortFW);
}
